﻿using DeviceDetectorNET.Cache;
using Framework.Caching.FreeRedis;
using Framework.Core.Attributes;
using Framework.Core.Consts;
using Framework.Core.Enums;
using Framework.SqlSugarCore.Repositories;
using Mapster;
using Microsoft.AspNetCore.Identity;
using my.abp.Application.Contracts.Dtos.Role;
using my.abp.Domain.IManagers.Menu;
using my.abp.Domain.IManagers.Org;
using my.abp.Domain.IManagers.Role;
using my.abp.Domain.IManagers.User;
using my.abp.Domain.Repositories.Org;
using my.abp.Domain.Repositories.Role;
using my.abp.Domain.Shared.Entities;
using my.abp.Domain.Shared.Enums;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Services;

namespace my.abp.Domain.Managers.Role
{
	public class SysRoleManager : DomainService, ISysRoleManager
	{
		private readonly ISysRoleRepository _sysRoleRep;
		private Framework.AspNetCore.User.CurrentUser _CurrentUser;
		private readonly ISysUserRoleManager _sysUserRoleManager;
		private readonly ISysMenuManager _sysMenuManager;
		private readonly ISysRoleOrgManager _sysRoleOrgManager;
		private readonly ISysRoleMenuManager _sysRoleMenuManager;
		private readonly IWantDistributedCache _sysCache;
		private readonly ISysOrgManager _sysOrgManager;

		
		public SysRoleManager(IWantDistributedCache sysCache, ISysRoleRepository sysRoleRep, ISysUserRoleManager sysUserRoleManager,
			ISysRoleOrgManager sysRoleOrgManager, ISysOrgManager sysOrgManager,
			ISysRoleMenuManager sysRoleMenuManager,ISysMenuManager sysMenuManager,Framework.AspNetCore.User.CurrentUser currentUser)
		{
			_sysRoleRep = sysRoleRep;
			_CurrentUser = currentUser;
			_sysUserRoleManager = sysUserRoleManager;
			_sysMenuManager = sysMenuManager;
			_sysRoleOrgManager = sysRoleOrgManager;
			_sysRoleMenuManager = sysRoleMenuManager;
			_sysCache = sysCache;
			_sysOrgManager = sysOrgManager;
		}

		public async Task<List<SysRole>> ListAsync(string Name, string Code, int pageNumber, int pageSize, RefAsync<int> total)
		{
			var queryable = await _sysRoleRep.AsQueryable();

			if (queryable == null)
			{
				total = 0;
				return null;
			}

			return await queryable.WhereIF(!_CurrentUser.SuperAdmin, u => u.CreateUserId == _CurrentUser.UserId) // 若非超管，则只能操作自己创建的角色
				.WhereIF(!string.IsNullOrWhiteSpace(Name), u => u.Name.Contains(Name))
				.WhereIF(!string.IsNullOrWhiteSpace(Code), u => u.Code.Contains(Code))
				.OrderBy(u => u.OrderNo)
				.ToPageListAsync(pageNumber, pageSize, total);
		}

		/// <summary>
		/// 获取角色列表
		/// </summary>
		/// <returns></returns>
		public async Task<ISugarQueryable<SysRole>> GetList()
		{
			// 当前用户已拥有的角色集合
			var roleIdList = _CurrentUser.SuperAdmin ? null : await _sysUserRoleManager.GetUserRoleIdList(_CurrentUser.UserId);

			var queryable = await _sysRoleRep.AsQueryable();
			return queryable.WhereIF(roleIdList != null, u => u.CreateUserId == _CurrentUser.UserId || roleIdList.Contains(u.Id)) // 若非超管，则只显示自己创建和已拥有的角色
				.OrderBy(u => u.OrderNo);
		}

		/// <summary>
		/// 增加角色
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public async Task AddRole(SysRole input, List<long> MenuIdList)
		{
			if (await _sysRoleRep.IsAnyAsync(u => u.Name == input.Name && u.Code == input.Code))
				throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D1006));

			var insertable = await _sysRoleRep.AsInsertable(input);
			var newRole = await insertable.ExecuteReturnEntityAsync();
			input.Id = newRole.Id;
			await UpdateRoleMenu(input, MenuIdList);
		}

		/// <summary>
		/// 更新角色菜单权限
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		private async Task UpdateRoleMenu(SysRole input, List<long> MenuIdList)
		{
			if (MenuIdList == null || MenuIdList.Count < 1)
				return;

			var menuIds = await _sysMenuManager.GetList(MenuIdList);
			await GrantMenu(new RoleMenuInput()
			{
				Id = input.Id,
				MenuIdList = menuIds.ToList()
			});
		}

		/// <summary>
		/// 授权角色菜单
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public async Task GrantMenu(RoleMenuInput input)
		{
			await _sysRoleMenuManager.GrantRoleMenu(input);
		}

		/// <summary>
		/// 更新角色
		/// </summary>
		/// <param name="input"></param>
		/// <param name="MenuIdList"></param>
		/// <returns></returns>
		/// <exception cref="UserFriendlyException"></exception>
		public async Task UpdateRole(SysRole input, List<long> MenuIdList)
		{
			if (await _sysRoleRep.IsAnyAsync(u => u.Name == input.Name && u.Code == input.Code && u.Id != input.Id))
				throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D1006));

			var updateable = await _sysRoleRep.AsUpdateable(input.Adapt<SysRole>());

			await updateable.IgnoreColumns(true)
				.IgnoreColumns(u => new { u.DataScope }).ExecuteCommandAsync();

			await UpdateRoleMenu(input, MenuIdList);
		}

		/// <summary>
		/// 删除角色
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		/// <exception cref="UserFriendlyException"></exception>
		public async Task DeleteRole(SysRole input)
		{
			var sysRole = await _sysRoleRep.GetFirstAsync(u => u.Id == input.Id) ?? 
				throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D1002));

			if (sysRole.Code == CommonConst.SysAdminRole)
				throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D1019));

			await _sysRoleRep.DeleteAsync(sysRole);

			// 级联删除角色机构数据
			await _sysRoleOrgManager.DeleteRoleOrgByRoleId(sysRole.Id);

			// 级联删除用户角色数据
			await _sysUserRoleManager.DeleteUserRoleByRoleId(sysRole.Id);

			// 级联删除角色菜单数据
			await _sysRoleMenuManager.DeleteRoleMenuByRoleId(sysRole.Id);
		}

		/// <summary>
		/// 授权角色数据范围
		/// </summary>
		/// <param name="Id"></param>
		/// <param name="DataScope"></param>
		/// <param name="OrgIdList"></param>
		/// <returns></returns>
		public async Task GrantDataScope(long Id, int DataScope, List<long> OrgIdList)
		{
			// 删除与该角色相关的用户机构缓存
			var userIdList = await _sysUserRoleManager.GetUserIdList(Id);

			var db = await _sysRoleRep.GetDbContextAsync();
			var ContextID = db.ContextID;
			foreach (var userId in userIdList)
			{
				_sysCache.Remove<List<long>,string>($"{CacheConst.KeyUserOrg}{userId}",CacheConst.cacheName);
				_sysCache.Remove<dynamic, string>($"{CacheConst.KeyRoleMaxDataScope}{userId}", CacheConst.cacheName);
			}

			var role = await _sysRoleRep.GetFirstAsync(u => u.Id == Id);
			var dataScope = DataScope;
			if (!_CurrentUser.SuperAdmin)
			{
				// 非超级管理员没有全部数据范围权限
				if (dataScope == (int)DataScopeEnum.All)
					throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D1016));

				// 若数据范围自定义，则判断授权数据范围是否有权限
				if (dataScope == (int)DataScopeEnum.Define)
				{
					var grantOrgIdList = OrgIdList;
					if (grantOrgIdList.Count > 0)
					{
						var orgIdList = await _sysOrgManager.GetUserOrgIdList();
						if (orgIdList.Count < 1)
							throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D1016));
						else if (!grantOrgIdList.All(u => orgIdList.Any(c => c == u)))
							throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D1016));
					}
				}
			}
			role.DataScope = (DataScopeEnum)dataScope;

			var updateable = await _sysRoleRep.AsUpdateable(role);
			await updateable.UpdateColumns(u => new { u.DataScope }).ExecuteCommandAsync();

			await _sysRoleOrgManager.GrantRoleOrg(Id,DataScope,OrgIdList);
		}

		public async Task<int> SetStatus(SysRole input)
		{
			if (!System.Enum.IsDefined(typeof(StatusEnum), input.Status))
				throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D3005));

			var updatealbe = await _sysRoleRep.AsUpdateable();
			return await updatealbe.SetColumns(u => u.Status == input.Status)
				.Where(u => u.Id == input.Id)
				.ExecuteCommandAsync();
		}
	}
}
